#include "preHeader.h"
#include "SocialData.h"
#include "CharacterMgr.h"
#include "Session/DBPSession.h"

enum SocialRemoveDataFlag
{
	SRDF_PREVENT_SYNC_TO_DB = 1 << 0,
	SRDF_PREVENT_SYNC_FOLLOWER = 1 << 1,
	SRDF_PREVENT_SYNC_MYLIST = 1 << 2,
};

SocialData::SocialData(Character* pOwner)
: m_pOwner(pOwner)
{
}

SocialData::~SocialData()
{
}

void SocialData::LoadFriendFromDB(social_friend&& tblVal)
{
	auto pChar = sCharacterMgr.GetCharacter(tblVal.friendId);
	if (pChar != NULL) {
		pChar->socialData.AddFollower(m_pOwner, FollowerType::Friend);
		m_friendList.emplace(tblVal.friendId, FriendInfo{pChar, tblVal});
	}
}

void SocialData::LoadIgnoreFromDB(social_ignore&& tblVal)
{
	auto pChar = sCharacterMgr.GetCharacter(tblVal.ignoreId);
	if (pChar != NULL) {
		pChar->socialData.AddFollower(m_pOwner, FollowerType::Ignore);
		m_ignoreList.emplace(tblVal.ignoreId, IgnoreInfo{pChar, tblVal});
	}
}

void SocialData::AddFollower(Character* pChar, FollowerType asType)
{
	m_followerList.emplace(pChar->guid.UID, FollowerInfo{pChar, asType});
}

void SocialData::RemoveFollower(Character* pChar, FollowerType asType)
{
	auto pair = m_followerList.equal_range(pChar->guid.UID);
	for (auto itr = pair.first; itr != pair.second;) {
		if (itr->second.asType == asType) {
			itr = m_followerList.erase(itr);
		} else {
			++itr;
		}
	}
}

GErrorCode SocialData::AddFriend(Character* pChar)
{
	if (IsFriend(pChar->guid)) {
		return CommonSuccess;
	}

	social_friend tblVal;
	tblVal.characterId = m_pOwner->guid.UID;
	tblVal.friendId = pChar->guid.UID;
	tblVal.createTime = GET_UNIX_TIME;
	m_friendList.emplace(tblVal.friendId, FriendInfo{pChar, tblVal});
	pChar->socialData.AddFollower(m_pOwner, FollowerType::Friend);

	NetPacket rpcReqPck(CDBP_NEW_SOCIAL_FRIEND);
	SaveToINetStream(tblVal, rpcReqPck);
	sDBPSession.RPCInvoke(rpcReqPck);

	RemoveIgnore(pChar);
	return CommonSuccess;
}

GErrorCode SocialData::RemoveFriend(Character* pChar, int flags)
{
	if (!IsFriend(pChar->guid)) {
		return CommonSuccess;
	}

	if ((flags & SRDF_PREVENT_SYNC_TO_DB) == 0) {
		NetPacket rpcReqPck(CDBP_DELETE_SOCIAL_FRIEND);
		rpcReqPck << m_pOwner->guid.UID << pChar->guid.UID;
		sDBPSession.RPCInvoke(rpcReqPck);
	}

	if ((flags & SRDF_PREVENT_SYNC_FOLLOWER) == 0) {
		pChar->socialData.RemoveFollower(m_pOwner, FollowerType::Friend);
	}
	if ((flags & SRDF_PREVENT_SYNC_MYLIST) == 0) {
		m_friendList.erase(pChar->guid.UID);
	}

	return CommonSuccess;
}

GErrorCode SocialData::AddIgnore(Character* pChar)
{
	if (IsIgnore(pChar->guid)) {
		return CommonSuccess;
	}

	social_ignore tblVal;
	tblVal.characterId = m_pOwner->guid.UID;
	tblVal.ignoreId = pChar->guid.UID;
	tblVal.createTime = GET_UNIX_TIME;
	m_ignoreList.emplace(tblVal.ignoreId, IgnoreInfo{pChar, tblVal});
	pChar->socialData.AddFollower(m_pOwner, FollowerType::Ignore);

	NetPacket rpcReqPck(CDBP_NEW_SOCIAL_IGNORE);
	SaveToINetStream(tblVal, rpcReqPck);
	sDBPSession.RPCInvoke(rpcReqPck);

	RemoveFriend(pChar);
	return CommonSuccess;
}

GErrorCode SocialData::RemoveIgnore(Character* pChar, int flags)
{
	if (!IsIgnore(pChar->guid)) {
		return CommonSuccess;
	}

	if ((flags & SRDF_PREVENT_SYNC_TO_DB) == 0) {
		NetPacket rpcReqPck(CDBP_DELETE_SOCIAL_IGNORE);
		rpcReqPck << m_pOwner->guid.UID << pChar->guid.UID;
		sDBPSession.RPCInvoke(rpcReqPck);
	}

	if ((flags & SRDF_PREVENT_SYNC_FOLLOWER) == 0) {
		pChar->socialData.RemoveFollower(m_pOwner, FollowerType::Ignore);
	}
	if ((flags & SRDF_PREVENT_SYNC_MYLIST) == 0) {
		m_ignoreList.erase(pChar->guid.UID);
	}

	return CommonSuccess;
}

void SocialData::OnRemoveCharacter()
{
	NetPacket rpcReqPck(CDBP_DELETE_ALL_SOCIAL_DATA);
	rpcReqPck << m_pOwner->guid.UID;
	sDBPSession.RPCInvoke(rpcReqPck);

	for (auto&[characterId, friendInfo] : m_friendList) {
		RemoveFriend(friendInfo.pChar,
			SRDF_PREVENT_SYNC_TO_DB | SRDF_PREVENT_SYNC_MYLIST);
	}
	m_friendList.clear();
	for (auto&[characterId, ignoreInfo] : m_ignoreList) {
		RemoveIgnore(ignoreInfo.pChar,
			SRDF_PREVENT_SYNC_TO_DB | SRDF_PREVENT_SYNC_MYLIST);
	}
	m_ignoreList.clear();

	for (auto&[characterId, followerInfo] : m_followerList) {
		auto& socialData = followerInfo.pChar->socialData;
		switch (followerInfo.asType) {
		case FollowerType::Friend:
			socialData.RemoveFriend(m_pOwner,
				SRDF_PREVENT_SYNC_TO_DB | SRDF_PREVENT_SYNC_FOLLOWER);
			break;
		case FollowerType::Ignore:
			socialData.RemoveIgnore(m_pOwner,
				SRDF_PREVENT_SYNC_TO_DB | SRDF_PREVENT_SYNC_FOLLOWER);
			break;
		}
	}
	m_followerList.clear();
}

bool SocialData::IsFriend(ObjGUID characterGuid) const
{
	return m_friendList.count(characterGuid.UID) != 0;
}

bool SocialData::IsIgnore(ObjGUID characterGuid) const
{
	return m_ignoreList.count(characterGuid.UID) != 0;
}
